Skip to content

fix(loon): 兼容 WK3 主天气并修复空气质量与预警数据 - #107

Open
hhhoratioxu wants to merge 8 commits into
NSRingo:mainfrom
hhhoratioxu:sync/loon-v3-and-air-quality
Open

hhhoratioxu wants to merge 8 commits into
NSRingo:mainfrom
hhhoratioxu:sync/loon-v3-and-air-quality

Conversation

@hhhoratioxu

@hhhoratioxu hhhoratioxu commented Nov 5, 2026 •

Copy link
Copy Markdown

🆕 New Features

  • 为 Loon 增加 WeatherKit v3 主天气 App 兼容入口,保留 v2 二进制处理、原版名称、原有 12 项参数默认值及 NSRingo 发布地址。Loon 使用独立的 .loon.bundle.js,其他客户端的原有模板与包版本策略保持不变。
  • availability 与普通空气质量标尺使用原生规则,HK/CN 自定义图例使用独立小脚本。
  • 新增第 13 项预警正文语言偏好 Auto / zh-Hans / en,默认 Auto 保持原行为。仅向当前所选来源请求其原生语言;来源不支持或返回原文/混合语言时,保留实际文字、签发单位和出处,不调用第三方翻译。显式偏好使用 und 消息语言标记及 no-store 详情响应,不改变主天气、空气质量等其他产品的语言。

🛠️ Bug Fixes

  • 修复主天气 App 的 JSON 状态、降水统计和预警 UUID 字节对象与原生读取器格式不一致的问题;未选择来源替换、选择 WeatherKit 或补充失败时,保留的 Apple 预警同样兼容。仅包含 forecastPeriodic/weatherChanges 的回应仍适配已知字段,不发供应商请求;补齐 restOfDay、分钟降水末尾转折与空分钟表的边界。
  • 修复 11 种内置算法的输入、单位、零浓度、插值和分级边界,保留六项有效浓度;AQ 等级比较先校验正整数或对应字符串。保留 Apple QWeather CO 的明确入口修复,避免重复转换。
  • 恢复原版指数目标列表、默认保留昨日对比及独立来源配置;算法选择不绕过目标标准,空目标和 None 停用本地指数转换。
  • 供应商失败或非法结果按产品保留 Apple 数据;彩云预警专属请求失败时,不借用同实例实况请求中的预警。没有实际补入预警字段时,保留 Apple 原集合、不可用状态、正文和验证头,避免制造可用的空预警。
  • 仅遍历已知 JSON 容器,保留未知子树;供应商合并导致最终输出超限时,回退到有界且已完成原生格式适配的 Apple 数据。
  • 修复未知预警有效期在正时区跨入 10000 年的兼容边界:兼容旧、新占位值,输出 9999-12-31T00:00:00Z;真实来源及 Apple 时间保持原样,未知值不制造 eventEndTime,真实已过期记录仍过滤。未将该旧边界归因为历史无正文的原因。

配置与运行边界

  • 后续精简已移除附加短时请求缓存、在途合并、队列/发起预算、失败冷却、摘要统计、额外地区推断和备用查询;旧保存值不能重新激活它们。正常单请求超时、位置网格条件请求与昨日对比缓存保留;所有已发请求等待原生回调后只完成一次。
  • 保留原有 LICENSE、贡献者和引用工作的署名。没有引入 Fork 分发地址、发布版本、机器配置或原始抓包,也没有提高既有 Loon 最低版本。

验证与证据范围

  • 用户实测反馈(2026-11-14):用户报告 Mac、iOS 和 Apple Watch 场景下 Loon 测试正常。此反馈未附具体版本、逐项用例或抓包,独立于下述可核验的 Mac Loon/Safari 预警证据;不据此声称我们已复核全部平台/全部功能,也不暗示存在 watchOS 原生 Loon 客户端。已有证据和未覆盖范围保留。
  • 本 PR 独立工作树完整回归 430/430,失败/跳过均为 0;实际生成的 Loon 脚本场景 52/52、表达式/路由/jq 15/15,13 项声明及原 12 项默认值均通过。0.0.0-test 仅用于本 PR 既有构建夹具,原 package.json 与锁文件保持不变。
  • periodic-only 回归:直接适配、release/development 入口。
  • unavailable alerts 回归:无有效补充时保留原产品与状态,实际编译脚本也覆盖已有 Apple 预警但仅返回空补充的场景。
  • Caiyun stale shared cache 回归:同一实例的实况成功、预警请求超时,结果保持预警不可用且为空,不读取实况请求里的预警。
  • Loon 已完成实际设备测试并通过本轮预警验收(2026-11-14,Mac Loon + Safari):候选插件实际加载 13 项参数,原有 12 项值保持一致;原生控件切换 Auto/中文/英文后,同一公开 Apple 预警入口成功显示仍有效的革吉大风黄色预警中文和英文正文、定义/指南、签发单位及对应来源链接,四次预警脚本执行完成且无脚本异常。完整中文原生 JSON 的正文、定义和五条指南已与本轮来源逐字核对;测试后恢复 Auto、原插件与现场,VPN 保持连接。本轮实机记录。
  • 产物与范围说明:上述实机证据来自与本 PR 共享业务源码的同源 Fork 构建,不代表本 PR 的 .loon.bundle.js 已重新完成真机安装验收。主天气、小时/每日预报、分钟雨、AQ/污染物和昨日对比的既有实机证据属于较早 f571a49 产物,本轮没有用新产物重新逐项实测,当前由回归与编译测试覆盖。英文完整原生 JSON、同一 HTTP 事务的 HTML/JSON 成对抓包、Surge 真机、其他地区/来源、原文回退的完整原生链路、iOS/watchOS、网络切换、长期 VPN 和资源量测仍未全面验证,不宣称本版全部功能或所有环境均通过实机验收。

输入检查方向参考 Patrick Yan 的 #108(24c3f931);已知容器遍历参考 hhh2210 的 #110(f4676fea,其 JSON 适配也注明源自 #107)。精确提交与 Apache-2.0 署名保留于源码。

实现与边界:当前后续修复与验证、兼容说明、原版行为核对、较早原生观察记录。Refs #106。

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 5, 2026 •

Copy link
Copy Markdown
Codex Review Summary: ✅ Completed

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-08T15:35:43.264827Z 355b5f5 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dac6b02970

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/process/ResponseJSONV3.mjs Outdated
if (!parameters.version || parameters.latitude === undefined || parameters.longitude === undefined || !Number.isFinite(latitude) || !Number.isFinite(longitude) || Math.abs(latitude) > 90 || Math.abs(longitude) > 180) return response;
let body;
try { body = JSON.parse(raw); } catch { return response; }
if (!object(body) || !productNames.some(name => object(body[name]) && object(body[name].metadata))) return response;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Adapt periodic-only v3 responses before returning

For a main-app v3 response containing only forecastPeriodic, this guard returns before normalization because productNames contains only the six replaceable products. The new rewrite in template/loon.handlebars still negotiates JSON for that request, so raw condition vectors and precipitation statistics reach the native reader instead of the required strings and scalars. The same periodic payload is normalized when an unrelated product such as currentWeather is also present. Include the known compatibility-only products in this acceptance check without making them provider-replacement targets.

Useful? React with 👍 / 👎.

Comment thread src/process/Response.mjs Outdated
Comment on lines +409 to +411
weatherAlerts.metadata = { ...weatherAlerts?.metadata, ...newWeatherAlerts.metadata };
weatherAlerts.detailsUrl = newWeatherAlerts.detailsUrl ?? weatherAlerts.detailsUrl;
weatherAlerts.alerts = WeatherAlerts.mergeAlerts(weatherAlerts?.alerts, newWeatherAlerts?.alerts);
weatherAlerts.alerts = WeatherAlerts.mergeAlerts(weatherAlerts?.alerts, activeProviderAlerts(newWeatherAlerts?.alerts));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve unavailable alert status when no warnings are merged

When Apple supplies an unavailable weatherAlerts collection with alerts: [] and the selected provider returns active warnings, the provider's new temporarilyUnavailable: false overwrites Apple's flag here. However, WeatherAlerts.mergeAlerts returns the empty destination immediately when it has no rows (src/class/WeatherAlerts.mjs:102-104), so all fetched warnings are discarded and the output incorrectly reports an available empty collection. Preserve the unavailable state unless warnings are actually installed; the same transition needs guarding in the development processor.

Useful? React with 👍 / 👎.

@hhhoratioxu
hhhoratioxu marked this pull request as draft November 5, 2026 04:26
VirgilClyne added a commit that referenced this pull request Nov 6, 2026
- WeatherKit2/ForecastNextHour import the named WK2 namespace; shared
  constructors move to WK2.Common.ForecastMinute / WK2.Common.UUID.
- WeatherKit3 gains a small FlatBufferRootProcessor subclass overriding only
  decode: a requested AQ child that fails to decode now yields null so the
  response keeps Apple's original package; a genuinely missing AQ still
  allows backfill. Encoding and other processor behavior is inherited.
- Response.dev drops direct protocol imports, raw generated-table checks
  and enum-table selection; MatchEnum takes the business object and the
  request version and picks WK2/WK3 enum tables internally.
- Port the shared PR #107/#108 fixes: epsilon-tolerant boundary ceiling in
  #CeilByPrecision, and idempotent QWeather CO unit handling in
  FixPollutantsUnits (explicit mg/m3 label, or the mislabeled Apple product
  only via appleProduct) with regression tests.
- Tests migrate static/dynamic protocol imports to the three-namespace API.
VirgilClyne added a commit that referenced this pull request Nov 6, 2026
- 拆分 WeatherKit 为 WeatherKit2/WeatherKit3 两个版本处理器,均基于
  @nsnanocat/flatbuffer-root 配置通用根表编解码;WK3 仅注册 AQ 根槽,
  其余产品保持原始 arena。
- WeatherKit3Processor 子类提供 decode 失败边界:已请求 AQ 读取或解码
  失败时返回 null 保留原包,物理缺失允许补齐(基于包的 decodeWithReport
  分类报告);checkFields 使用包的 inspectTable 做已验证字段数校验。
- 升级 @NSRingo/weatherkit 至 2.0.0(Common/WK2/WK3 命名空间)与
  @nsnanocat/flatbuffer-root 至 ^1.1.0;共用构造器经 WK2.Common 引用。
- Response.dev 移除协议包直接导入、枚举表选择与原始生成表检查;
  MatchEnum 改为按请求版本内部选择枚举表。
- 移植 PR #107/#108 共同确认的修复:#CeilByPrecision 取整 EPSILON 容差、
  FixPollutantsUnits 的 CO 单位幂等转换(appleProduct 入口)。
- WK3 与 WK2 的函数顺序、命名、参数排版对齐;两个 class 均补 JSDoc。
- 新增平台模拟回放测试(dist bundle、Surge 语义模拟)与 CO 单位回归。
VirgilClyne added a commit that referenced this pull request Nov 6, 2026
- 拆分 WeatherKit 为 WeatherKit2/WeatherKit3 两个版本处理器,均基于
  @nsnanocat/flatbuffer-root 配置通用根表编解码;WK3 仅注册 AQ 根槽,
  其余产品保持原始 arena。
- WeatherKit3Processor 子类提供 decode 失败边界:已请求 AQ 读取或解码
  失败时返回 null 保留原包,物理缺失允许补齐(基于包的 decodeWithReport
  分类报告);checkFields 使用包的 inspectTable 做已验证字段数校验。
- 升级 @NSRingo/weatherkit 至 2.0.0(Common/WK2/WK3 命名空间)与
  @nsnanocat/flatbuffer-root 至 ^1.1.0;共用构造器经 WK2.Common 引用。
- Response.dev 移除协议包直接导入、枚举表选择与原始生成表检查;
  MatchEnum 改为按请求版本内部选择枚举表。
- 移植 PR #107/#108 共同确认的修复:#CeilByPrecision 取整 EPSILON 容差、
  FixPollutantsUnits 的 CO 单位幂等转换(appleProduct 入口)。
- WK3 与 WK2 的函数顺序、命名、参数排版对齐;两个 class 均补 JSDoc。
- 新增平台模拟回放测试(dist bundle、Surge 语义模拟)与 CO 单位回归。
VirgilClyne added a commit that referenced this pull request Nov 6, 2026
- 拆分 WeatherKit 为 WeatherKit2/WeatherKit3 两个版本处理器,均基于
  @nsnanocat/flatbuffer-root 配置通用根表编解码;WK3 仅注册 AQ 根槽,
  其余产品保持原始 arena。
- WeatherKit3Processor 子类提供 decode 失败边界:已请求 AQ 读取或解码
  失败时返回 null 保留原包,物理缺失允许补齐(基于包的 decodeWithReport
  分类报告);checkFields 使用包的 inspectTable 做已验证字段数校验。
- 升级 @NSRingo/weatherkit 至 2.0.0(Common/WK2/WK3 命名空间)与
  @nsnanocat/flatbuffer-root 至 ^1.1.0;共用构造器经 WK2.Common 引用。
- Response.dev 移除协议包直接导入、枚举表选择与原始生成表检查;
  MatchEnum 改为按请求版本内部选择枚举表。
- 移植 PR #107/#108 共同确认的修复:#CeilByPrecision 取整 EPSILON 容差、
  FixPollutantsUnits 的 CO 单位幂等转换(appleProduct 入口)。
- WK3 与 WK2 的函数顺序、命名、参数排版对齐;两个 class 均补 JSDoc。
- 新增平台模拟回放测试(dist bundle、Surge 语义模拟)与 CO 单位回归。
VirgilClyne added a commit that referenced this pull request Nov 6, 2026
- 拆分 WeatherKit 为 WeatherKit2/WeatherKit3 两个版本处理器,均基于
  @nsnanocat/flatbuffer-root 配置通用根表编解码;WK3 仅注册 AQ 根槽,
  其余产品保持原始 arena。
- WeatherKit3Processor 子类提供 decode 失败边界:已请求 AQ 读取或解码
  失败时返回 null 保留原包,物理缺失允许补齐(基于包的 decodeWithReport
  分类报告);checkFields 使用包的 inspectTable 做已验证字段数校验。
- 共用构造器经 WK2.Common 引用;Response.dev 移除协议包直接导入、
  枚举表选择与原始生成表检查;MatchEnum 改为按请求版本内部选择枚举表。
- 移植 PR #107/#108 共同确认的修复:#CeilByPrecision 取整 EPSILON 容差、
  FixPollutantsUnits 的 CO 单位幂等转换(appleProduct 入口)。
- WK3 与 WK2 的函数顺序、命名、参数排版对齐;两个 class 均补 JSDoc。
- 新增平台模拟回放测试(dist bundle、Surge 语义模拟)与 CO 单位回归。
- dev 模块模板的 weather 规则拆分为独立的 v2/v3 条目并修正命名。
@hhhoratioxu hhhoratioxu changed the title fix(loon): 兼容 iOS 27.3 WK3 并修复空气质量与供应商失败处理 fix(loon): 兼容 WK3 主天气并修复空气质量与预警数据 Nov 8, 2026
@hhhoratioxu
hhhoratioxu marked this pull request as ready for review November 8, 2026 15:22

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 355b5f5dad

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/class/ColorfulClouds.mjs Outdated
Comment on lines 379 to 381
await this.#RealTime("alerts");
if (!Array.isArray(this.#cache.alert?.content)) throw Error(JSON.stringify(this.#cache.alert));
weatherAlerts = { ...failedWeatherAlerts, ...this.#CreateWeatherAlerts(this.#cache.alert) };

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Consume the alert-specific response instead of shared cache state

When a Loon response fetches Caiyun current weather and alerts concurrently, the default TTLs allow a 30-second-old realtime response to satisfy the current-weather call while the alert call must refresh it. The current call repopulates #cache.alert, so if the alert refresh times out, #RealTime('alerts') returns {} but this code still converts the other call’s stale alerts and marks them available. This bypasses the 15-second alert TTL and failure fallback, allowing stale warnings to overwrite Apple warning fields. Consume alerts from the response returned by this specific call rather than the instance-wide cache slot.

Useful? React with 👍 / 👎.

Remove the nine optional cache, coalescing, request budget, cooldown,
statistics, region fallback and alternate-provider controls. Keep original
source settings, per-request timeouts and Apple failure fallback.

Preserve unavailable Apple warnings unless enrichment changes actual data;
retain opaque JSON containers and a normalized Apple fallback on overflow.
Cover periodic and minute-rain edge cases and validate AQ comparison levels.

Add source-native warning language preferences with Auto preserving old
behavior. Normalize reserved expiry values without changing genuine times
or manufacturing an event end. Preserve the original twelve defaults.

Keep the PR's upstream release URLs, original display name, independent
.loon.bundle.js files, package/lockfile policy and attribution. Retain all
seven existing commits. Credit the referenced input-validation direction
from Patrick Yan (NSRingo#108, 24c3f93) and known-container traversal from
hhh2210 (NSRingo#110, f4676fe), as documented in the source.

Validation: 430/430 regressions; 52 compiled Loon scenarios; 15 rewrite/jq
checks; 13 declarations with all twelve original defaults preserved.
Native evidence and remaining limits are documented separately.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant